package com.kvn.universal.filter.lock;

import java.util.ArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.kvn.universal.core.Invoker;
import com.kvn.universal.core.InvokerContext;
import com.kvn.universal.core.lock.LockContext;
import com.kvn.universal.core.lock.LockHolder;
import com.kvn.universal.exception.UniversalChainErrors;
import com.kvn.universal.filter.Filter;

/**
 * @author wzy
 * @date 2017年7月14日 上午10:15:16
 */
public class LockFilter implements Filter {
	private final static Logger logger = LoggerFactory.getLogger(LockFilter.class);

	@Override
	public Object invokeWapper(Invoker invoker, InvokerContext invokerContext) {
		ArrayList<LockHolder> lockHolderLs = invokerContext.getExtendContext(LockContext.class).getLockHolderLs();
		/** 1. 批量上锁 **/
		for (int i = 0; i < lockHolderLs.size(); i++) {
			RedisReentrantLock lock = RedisReentrantLock.getLock(lockHolderLs.get(i).getKey());
			lockHolderLs.get(i).setLock(lock);
			try {
				lock.lock(); // 上锁
				logger.info("LockFilter lock success, lock key is {}", lockHolderLs.get(i).getKey());
			} catch (Exception e) {
				logger.error("LockFilter lock error, need lock {} locks, current index is {}, current lock key is {}", lockHolderLs.size(), i,
						lockHolderLs.get(i).getKey(), e);
				if (lockHolderLs.size() <= 1 || i == 0) {
					throw UniversalChainErrors.LOCK_ERROR.exp(e);
				}
				// 当要上多个锁，在中间某个锁获取失败时，将前面的锁释放
				for (int j = i - 1; j >= 0; j--) {
					RedisReentrantLock previousLock = lockHolderLs.get(j).getLock();
					try {
						previousLock.unlock();
					} catch (Exception e1) {
						// 不处理，记录异常日志
						logger.error("LockFilter unlock error when handle lock error", e1);
					}
				}

				throw UniversalChainErrors.LOCK_ERROR.exp(e);
			}
		}
		
		try {
			/** 2. 执行业务 **/
			return invoker.invoke(invokerContext);
		} finally {
			/** 3. 批量解锁 **/
			for (int i = lockHolderLs.size() - 1; i >= 0; i--) {
				RedisReentrantLock lock = lockHolderLs.get(i).getLock();
				try {
					lock.unlock(); // 解锁
					logger.info("LockFilter unlock success, lock key is {}", lockHolderLs.get(i).getKey());
				} catch (Exception e) {
					// 不处理，记录异常日志
					logger.error("LockFilter unlock error after invoker invoke", e);
				}
			}
		}
	}

}
